#include "RR.h"
#include <stdio.h>
#include <stdlib.h>

/**
 * 函数: calculateTimes
 * 功能: 根据时间片轮转调度算法计算每个进程的完成时间、周转时间和等待时间
 *
 * 参数:
 *  - processes: 指向包含多个进程信息的数组
 *  - n: 进程数量
 *  - time_slice: 时间片长度
 *
 * 描述:
 *  计算进程的完成时间，周转时间和等待时间并存在结构体中即可
 */
/*P1 完成时间: 28, 周转时间: 28, 等待时间: 18  */
/*P2 完成时间: 22, 周转时间: 21, 等待时间: 15  */
/*P3 完成时间: 26, 周转时间: 24, 等待时间: 16  */
/*P4 完成时间: 16, 周转时间: 13, 等待时间: 9  */
/*Process processes[] = { { 1, 0, 10, 10, 0, 0, 0 },*/
                        /*{ 2, 1, 6, 6, 0, 0, 0 },*/
                        /*{ 3, 2, 8, 8, 0, 0, 0 },*/
                        /*{ 4, 3, 4, 4, 0, 0, 0 } };*/
//    int pid;               // 进程ID，用于标识进程  
//    int arrival_time;      // 到达时间，进程进入系统的时间  
//    int burst_time;        // 运行时间，进程需要的总CPU时间  
//    int remaining_time;    // 剩余运行时间，用于记录进程还需要多少时间完成  
//    int completion_time;   // 完成时间，进程完成执行的时间  
//    int turnaround_time;   // 周转时间，进程从到达到完成所经历的总时间 (完成时间 - 到达时间)  
//    int waiting_time;      // 等待时间，进程在就绪队列中等待的时间 (周转时间 - 运行时间)  
void
calculateTimes (Process *processes, int n, int time_slice)
{
  // TODO
  int* sortP = (int *)malloc(n * sizeof(int));
  int* indexP = (int *)malloc(n * sizeof(int));
  for (int i=0; i<n; ++i) {
    sortP[i] = processes[i].arrival_time;
    indexP[i] = i;
  }
  for (int i=1; i<n; ++i) {
    for (int j=0; j<i; ++j) {
      if (sortP[j] > processes[i].arrival_time) {
        for (int k=i-1; k>j; --k) {
          sortP[k+1] = sortP[k];
          indexP[k+1] = indexP[k];
        }
        sortP[j] = processes[i].arrival_time;
        indexP[j] = i; 
      }
    }
  }

  int index = 0;
  int sum_time = 0;
  do {
    int finish = 1;
    for (int i=0; i<n; ++i) {
      if (processes[i].remaining_time > 0) {
        finish = 0;
        break;
      }
    }
    if (finish) { break;}

    int cur_pid = indexP[index];
    while(processes[cur_pid].remaining_time <= 0) {
      index = (index + 1) % n;
      cur_pid = indexP[index];
    }
    while (sum_time < processes[cur_pid].arrival_time) {
      int beishu = processes[cur_pid].arrival_time / time_slice + 1;
      sum_time = beishu * time_slice;
      continue;
    }

    int run_time = processes[cur_pid].remaining_time > time_slice ? time_slice : processes[cur_pid].remaining_time;
    if (sum_time <= processes[cur_pid].arrival_time) {
      int real_time = time_slice - processes[cur_pid].arrival_time;
      run_time = real_time > run_time ? run_time :real_time ;
    }
    processes[cur_pid].remaining_time -= run_time; 
    if (processes[cur_pid].remaining_time > 0 && processes[cur_pid].waiting_time == 0) {
      processes[cur_pid].waiting_time = time_slice - run_time;
    }
    processes[cur_pid].completion_time += run_time;
    processes[cur_pid].turnaround_time = processes[cur_pid].completion_time - processes[cur_pid].arrival_time;

    index = (index + 1) % n;
    sum_time += run_time;

    for (int i=0; i<n; ++i) {
      if (cur_pid != i && processes[i].remaining_time > 0) {
        processes[i].completion_time += run_time;
        if (sum_time >= processes[i].arrival_time) {
          if (processes[i].waiting_time <= 0 && processes[i].turnaround_time <= 0)
            processes[i].waiting_time += sum_time - processes[i].arrival_time;
          else
            processes[i].waiting_time += run_time;
        }
      }
    }
  } while (1);
}
